﻿#include "service_context_impl.hh"
#include "../../src/box/service_box.hh"
#include "../../src/detail/box_alloc.hh"
#include "../../src/detail/http_base_impl.hh"
#include "../../src/detail/memory_allocator_impl.hh"
#include "../../src/detail/scheduler_impl.hh"
#include "../../src/detail/service_logger_impl.hh"
#include "../../src/repo/src/include/root/coroutine/coroutine.h"
#include "../../src/repo/src/include/root/rpc_defines.h"
#include "../../src/repo/src/include/root/rpc_root.h"
#include "../../thirdparty/klogger/klogger/interface/logger.h"
#include "../console/box_console_impl.hh"
#include "../console/console_impl.hh"
#include "../detail/command_impl.hh"
#include "../detail/coro_runner_impl.hh"
#include "../detail/csv_reader_impl.hh"
#include "../detail/lang_impl.hh"
#include "../detail/local_system_time_impl.hh"
#include "../detail/proxy_handler_impl.hh"
#include "../detail/redis_impl.hh"
#include "../util/lua/lua_helper.hh"
#include "../util/object_pool.hh"
#include "../util/util_impl.hh"
#include "box_alloc.hh"
#include <memory>

kratos::service::ServiceContextImpl::ServiceContextImpl(ServiceBox *box) {
  box_ = box;
}

kratos::service::ServiceContextImpl::~ServiceContextImpl() { box_ = nullptr; }

auto kratos::service::ServiceContextImpl::register_service(
    const std::string &name) -> bool {
  if (name.empty()) {
    return false;
  }
  return box_->register_service(name);
}

auto kratos::service::ServiceContextImpl::unregister_service(
    const std::string &name) -> bool {
  if (name.empty()) {
    return false;
  }
  return box_->unregister_service(name);
}

auto kratos::service::ServiceContextImpl::shutdown() -> void {
  box_->write_log(lang::LangID::LANG_SERVICE_CONTEXT_REQUEST_SHUTDOWN,
                  klogger::Logger::WARNING);
  box_->set_wait_stop_flag();
}

void kratos::service::ServiceContextImpl::sleep_co(std::time_t ms) {
  if (coro_is_main()) {
    // 只能在子协程内调用
    return;
  }
  coro_sleep(ms);
}

auto kratos::service::ServiceContextImpl::get_argument() const
    -> const argument::BoxArgument & {
  return box_->get_argument();
}

auto kratos::service::ServiceContextImpl::write_log_line(
    int log_level, const std::string &log_line) -> void {
  if (log_line.empty()) {
    return;
  }
  if (box_) {
    box_->write_log_line(log_level, log_line);
  }
}

auto kratos::service::ServiceContextImpl::get_config() const
    -> kratos::config::BoxConfig & {
  return box_->get_config();
}

auto kratos::service::ServiceContextImpl::try_get_transport(
    const std::string &name) -> std::shared_ptr<rpc::Transport> {
  if (name.empty()) {
    return nullptr;
  }
  return box_->try_get_transport(name);
}

auto kratos::service::ServiceContextImpl::get_transport_sync(
    const std::string &name, std::time_t timeout)
    -> std::shared_ptr<rpc::Transport> {
  if (name.empty()) {
    return nullptr;
  }
  return box_->get_transport_sync(name, timeout);
}

auto kratos::service::ServiceContextImpl::get_transport_co(
    const std::string &service_name, std::time_t timeout)
    -> std::shared_ptr<rpc::Transport> {
  if (service_name.empty()) {
    return nullptr;
  }
  if (coro_is_main()) {
    // 只能在子协程内调用
    return nullptr;
  }
  std::shared_ptr<rpc::Transport> trans;
  std::time_t count = 1;
  while (true) {
    trans = try_get_transport(service_name);
    if (trans) {
      return trans;
    }
    coro_sleep(1);
    if (count < timeout) {
      count += 1;
    } else {
      break;
    }
  }
  return nullptr;
}

auto kratos::service::ServiceContextImpl::verbose(const std::string &log)
    -> void {
  write_log_line(klogger::Logger::VERBOSE, log);
}

auto kratos::service::ServiceContextImpl::info(const std::string &log) -> void {
  write_log_line(klogger::Logger::INFORMATION, log);
}

auto kratos::service::ServiceContextImpl::diagnose(const std::string &log)
    -> void {
  write_log_line(klogger::Logger::DIAGNOSE, log);
}

auto kratos::service::ServiceContextImpl::warn(const std::string &log) -> void {
  write_log_line(klogger::Logger::WARNING, log);
}

auto kratos::service::ServiceContextImpl::except(const std::string &log)
    -> void {
  write_log_line(klogger::Logger::EXCEPTION, log);
}

auto kratos::service::ServiceContextImpl::fail(const std::string &log) -> void {
  write_log_line(klogger::Logger::FAILURE, log);
}

auto kratos::service::ServiceContextImpl::fatal(const std::string &log)
    -> void {
  write_log_line(klogger::Logger::FATAL, log);
}

auto kratos::service::ServiceContextImpl::new_scheduler()
    -> std::unique_ptr<kratos::service::Scheduler> {
  return std::unique_ptr<kratos::service::Scheduler>(
      new kratos::service::SchedulerImpl(box_));
}

auto kratos::service::ServiceContextImpl::new_http()
    -> std::unique_ptr<kratos::http::HttpBase> {
  return std::unique_ptr<kratos::http::HttpBase>(
      new kratos::http::HttpBaseImpl(box_));
}

auto kratos::service::ServiceContextImpl::new_coro_runner()
    -> std::unique_ptr<CoroRunner> {
  return std::unique_ptr<CoroRunner>(new CoroRunnerImpl(this));
}

auto kratos::service::ServiceContextImpl::get_allocator() -> MemoryAllocator & {
  static MemoryAllocatorImpl impl;
  return impl;
}

auto kratos::service::ServiceContextImpl::new_command()
    -> std::unique_ptr<Command> {
  return std::unique_ptr<Command>(new CommandImpl(box_->get_command_manager()));
}

auto kratos::service::ServiceContextImpl::new_redis()
    -> std::unique_ptr<kratos::redis::Redis> {
  return std::unique_ptr<kratos::redis::Redis>(
      (new kratos::redis::RedisImpl(box_)));
}

auto kratos::service::ServiceContextImpl::allocate(std::size_t size) -> void * {
  return reinterpret_cast<void *>(kratos::service::box_malloc(size));
}

auto kratos::service::ServiceContextImpl::deallocate(void *p) -> void {
  return kratos::service::box_free(p);
}

auto kratos::service::ServiceContextImpl::get_statistics() -> ProcStat * {
  return box_->get_proc_stat();
}

auto kratos::service::ServiceContextImpl::get_module_logger(
    const std::string &name) -> std::unique_ptr<ServiceLogger> {
  return std::unique_ptr<ServiceLogger>(new ServiceLoggerImpl(name, box_));
}

auto kratos::service::ServiceContextImpl::get_local_time()
    -> std::unique_ptr<kratos::time::LocalTime> {
  return std::unique_ptr<kratos::time::LocalTime>(
      new kratos::time::LocalTimeImpl());
}

auto kratos::service::ServiceContextImpl::get_proxy_handler()
    -> rpc::ProxyHandler * {
  return box_->get_proxy_handler();
}

auto kratos::service::ServiceContextImpl::get_rpc() -> rpc::Rpc * {
  return box_->get_rpc();
}

auto kratos::service::ServiceContextImpl::get_rpc_statistics()
    -> rpc::StubCallStatistics * {
  return rpc::getStatistic();
}

auto kratos::service::ServiceContextImpl::new_csv_manager() -> CsvManagerPtr {
  return std::unique_ptr<kratos::util::CsvManagerImpl>(
      new kratos::util::CsvManagerImpl(box_));
}

auto kratos::service::ServiceContextImpl::new_box_console(
    const std::string &name) -> BoxConsolePtr {
  return std::unique_ptr<kratos::console::BoxConsoleImpl>(
      new kratos::console::BoxConsoleImpl(name, box_->get_console()));
}

auto kratos::service::ServiceContextImpl::new_lua_service() -> LuaServicePtr {
  return std::unique_ptr<kratos::lua::LuaServiceImpl>(
      new kratos::lua::LuaServiceImpl(box_));
}

auto kratos::service::ServiceContextImpl::new_util() -> UtilPtr {
  return std::unique_ptr<kratos::service::UtilImpl>(
      new kratos::service::UtilImpl());
}

auto kratos::service::ServiceContextImpl::get_box() -> ServiceBox * {
  return box_;
}
